import olOverlay from "ol/Overlay.js";
import { transform, get as getProjection } from "ol/proj.js";
import { toStringHDMS } from "ol/coordinate.js";
class OverlayHandler {
  constructor(ol2d, ol3d, scene) {
    this.ol2d = ol2d;
    this.ol3d = ol3d;
    this.scene = scene;

    this.staticOverlay = new olOverlay({
      element: document.getElementById("popup"),
    });

    this.ol2d.addOverlay(this.staticOverlay);

    this.options = {
      boostrap: false,
      add: true,
    };

    this.ol2d.on("click", this.onClickHandlerOL.bind(this));
    if (this.ol3d && this.scene) {
      const eventHandler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
      eventHandler.setInputAction(
        this.onClickHandlerCS.bind(this),
        Cesium.ScreenSpaceEventType["LEFT_CLICK"]
      );
    }
  }

  onClickHandlerOL(event) {
    const coordinates = event.coordinate;
    const hdms = toStringHDMS(transform(coordinates, "EPSG:4326", "EPSG:4326"));
    const overlay = this.getOverlay();
    overlay.setPosition(coordinates);
    this.setOverlayContent(overlay, hdms);
  }

  onClickHandlerCS(event) {
    if (event.position.x === 0 && event.position.y === 0) {
      return;
    }

    const ray = this.scene.camera.getPickRay(event.position);
    const cartesian = this.scene.globe.pick(ray, scene);
    if (!cartesian) {
      return;
    }
    const cartographic =
      scene.globe.ellipsoid.cartesianToCartographic(cartesian);
    let coords = [
      Cesium.Math.toDegrees(cartographic.longitude),
      Cesium.Math.toDegrees(cartographic.latitude),
    ];

    const height = scene.globe.getHeight(cartographic);
    if (height) {
      coords = coords.concat([height]);
    }

    const transformedCoords = transform(
      coords,
      getProjection("EPSG:4326"),
      "EPSG:4326"
    );
    const hdms = toStringHDMS(coords);
    const overlay = this.getOverlay();
    overlay.setPosition(transformedCoords);
    this.setOverlayContent(overlay, hdms);
  }

  getOverlay() {
    if (this.options.add) {
      return this.addOverlay();
    }

    return this.staticOverlay;
  }

  setOverlayContent(overlay, hdms) {
    const element = overlay.getElement();
    if (this.options.boostrap) {
      const div = document.createElement("div");
      div.onclick = this.onCloseClick.bind(this, overlay, this.options.add);
      div.innerHTML = `<p>当前点击位置:</p><code>${hdms}</code>`;
      $(element).popover("destroy");
      $(element).popover({
        placement: "top",
        animation: false,
        html: true,
        content: div,
      });
      $(element).popover("show");
    } else {
      // 兼容 Vue3 动态渲染，childNodes 可能为 NodeList
      let closer = null;
      let content = null;
      for (let i = 0; i < element.childNodes.length; i++) {
        const child = element.childNodes[i];
        if (child.id === "popup-content") {
          content = child;
        } else if (child.id === "popup-closer") {
          closer = child;
        }
      }
      if (content) {
        content.innerHTML = `<p>当前点击位置:</p><code>${hdms}</code>`;
      }
      if (closer) {
        // 先解绑再绑定，防止多次绑定
        closer.onclick = null;
        closer.addEventListener(
          "click",
          (e) => {
            e.preventDefault();
            this.onCloseClick(overlay, this.options.add);
          },
          { once: true }
        );
      }
    }
  }

  onCloseClick(overlay, add) {
    if (add) {
      // 兼容多次点击和已被移除的overlay
      try {
        this.ol2d.removeOverlay(overlay);
      } catch (e) {
        // 忽略异常
      }
      // 彻底隐藏DOM
      const el = overlay.getElement();
      if (el && el.parentNode) {
        el.parentNode.removeChild(el);
      }
    } else {
      overlay.setPosition(undefined);
    }
  }

  addOverlay() {
    let element = document.getElementById("popup").cloneNode(true);
    const overlay = new olOverlay({ element });
    this.ol2d.addOverlay(overlay);
    return overlay;
  }
}
export default OverlayHandler;
